﻿using Hangfire;
using Hangfire.MemoryStorage;
namespace D.Wx.HangfireJobUtils
{
    /// <summary>
    /// 定时任务
    /// 持久化保存任务、队列、统计信息：默认使用SQL Server，也可以配合消息队列来降低队列处理延 迟，或配置使用Redis来获得更好的性能表现
    /// 内置自动重试机制：可以设定重试次数，还可以手动在控制台重启任务
    /// 除了调用静态方法外还支持实例方法能够捕获多语言状态：即可以把调用者的Thread.CurrentCulture和Thread.CurrentUICulture信息同任务持久保存在一起，以便任务执行的时候多语言信息是一致的
    /// 支持任务取消：使用CancellationToken这样的机制来处理任务取消逻辑
    /// 支持IoC容器：目前支持Ninject和Autofac比较常用的开源IoC容器
    /// 支持Web集群：可以在一台或多台机器上运行多个Hangfire实例以便实现冗余备份
    /// 支持多队列：同一个Hangfire实例可以支持多个队列，以便更好的控制任务的执行方式
    /// 并发级别的控制：默认是处理器数量的5倍工作行程，当然也可以自己设定
    /// 具备很好的扩展性：有很多扩展点来控制持久存储方式、IoC容器支持等
    /// </summary>
    public static class HangfireUtil
    {
        /// <summary>
        /// 启用Hangfire服务
        /// 需要程序包：Hangfire.AspNetCore包含Hangfire.Core
        /// </summary>
        /// <param name="services"></param>
        public static void AddMyHangfire(this IServiceCollection services)
        {
            services.AddHangfire(config =>
            {
                config.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)  //设置兼容性
                      .UseColouredConsoleLogProvider() //彩色控制台
                      .UseSimpleAssemblyNameTypeSerializer()  //使用简单程序集名称类型序列化
                      .UseRecommendedSerializerSettings() //使用推荐的序列化配置
                      .UseStorage(new MemoryStorage()); // 使用内存缓存

                #region 使用SQLServer存储 需要Hangfire.SqlServer包 ，先手动创建数据库

                //.UseSqlServerStorage("sql连接字符串", new SqlServerStorageOptions()
                //{
                //    CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),//超时时间
                //    SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),//滑动超时
                //    QueuePollInterval = TimeSpan.Zero,//队列轮训间隔
                //    UseRecommendedIsolationLevel = true,//出列时是否需要锁
                //    UsePageLocksOnDequeue = true,
                //    DisableGlobalLocks = true//是否禁用全局锁
                //});

                #endregion
            });

            //将Hangfire处理服务器添加为IHostedService
            //此处添加后就不需要使用HangfireServer中间件，无需调用app.UseHangfireServer()。
            //services.AddHangfireServer(); 
            services.AddHangfireServer();
        }

        public static void UseMyHangfire(this IApplicationBuilder app)
        {
            // Hangfire仪表板板只允许本地 https://localhost:5000/hangfire访问，需要配置仪表板授权才可以远程访问
            app.UseHangfireDashboard("/job");

            //需要包：Hangfire.AspNetCore 第一个参数是仪表盘访问路径，第二个参数是仪表盘配置，其中可以配置授权，此处添加了一个用户名密码
            //app.UseHangfireDashboard("/hangfire", new DashboardOptions()
            //{
            //    //需要包：Hangfire.Dashboard.BasicAuthorization , 自定义权限验证
            //    Authorization = new CustomerHangfireAuthorizationFilter[] { new CustomerHangfireAuthorizationFilter() }
            //});
        }
    }
}


//3.创建任务
//①一次性任务，立即执行
//string jobId = BackgroundJob.Enqueue(() => Console.WriteLine("你好"));
//参数是任务的表达式目录树。 

//②定期任务，多次执行
//RecurringJob.AddOrUpdate(() => Console.WriteLine("你好"), "0/2 * * * * ?");
//第一个参数是任务的表达式目录树，第二个参数是Cron表达式。此处表示从0秒开始，每2秒执行一次。

//③延迟任务，定点执行
//string jobId = BackgroundJob.Schedule(() => Console.WriteLine("延迟"), TimeSpan.FromSeconds(10));
//第一个参数是任务的表达式目录树，第二个参数是TimeSpan，在指定时间间隔后执行，仅执行一次。

//④延续任务，在某个任务完成后执行
////第一个任务
//string jobId = BackgroundJob.Enqueue(() => Console.WriteLine("你好"));

////在第一个任务执行之后执行
//string jobId2 = BackgroundJob.ContinueJobWith(jobId, () => Console.WriteLine("继续任务"));
//第一个参数是上一个任务的唯一标志符，第二个参数是任务的表达式目录树。

//⑤传递依赖
//public interface IEmailHelper
//{
//    void Send(string msg);
//}

//public class EmailHelper : IEmailHelper
//{
//    public void Send(string msg)
//    {
//        Console.WriteLine("发送邮件：" + msg);
//    }
//}

////传递IEmailHelper，执行里面的方法
//string jobId = BackgroundJob.Enqueue<IEmailHelper>(s => s.Send("你好"));
//使用应用程序里的其他类来执行任务并保持代码简洁。


//4.启动服务
//var serverOptions = new BackgroundJobServerOptions()
//{
//    //服务轮训时间  默认是15秒
//    SchedulePollingInterval = TimeSpan.FromSeconds(1)
//};
//using (var server = new BackgroundJobServer(serverOptions))
//{
//    Console.WriteLine("Hangfire Server started. Press any key to exit...");
//    Console.ReadKey();
//} 
